//-----------------------------------------------------------------------
// <copyright file="XslTransform.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Andy Reeves</author>
// <email>andyr</email>
// <date>2004-03-23</date>
// <summary>Xsl Tranforms an xml file</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.Xml
{
    using System;
    using System.IO;
    using System.Xml;
    using System.Xml.Xsl;
    using System.Xml.XPath;
    using System.Globalization;

    using Microsoft.Build.Framework;

    /// <summary>
    /// Xsl an Xml file. This version is quite simplistic and doesn't support
    /// chaining or parameters.
    /// </summary>
    /// <remarks>
    /// <code><![CDATA[
    /// <Xml.XslTransform
    ///             XmlFile="xmlFile"
    ///                Path="path"
    ///                Output="output"
    ///             XslFile="xslFile"
    ///             ResultFile="resultFile"
    ///                Extension="extension"
    /// </Xml.XslTransform>
    /// ]]></code>
    /// <para>where:</para>
    /// <para><i>xmlFile (Optional)</i></para>
    /// <para>The full path and filename of the xml file to be transformed.  This is only used in conjunction with the ResultFile property.</para>
    /// <para><i>xslFile (Required)</i></para>
    /// <para>The full path and filename of the xsl file to be used in the transformation.</para>
    /// <para><i>path (Optional)</i></para>
    /// <para>The path to a folder containing xml files that require transforming.  This is only used in conjunction with the Output property.</para>
    /// <para><i>output (Optional)</i></para>
    /// <para>The path to a folder where transformed files will be placed.  This is only used in conjunction with the Path property.</para>
    /// <para><i>resultFile (Optional)</i></para>
    /// <para>The full path and filename of the result of the transformation. This file will be created if it does not exist.  This is only used in conjunction with the XmlFile property.</para>
    /// <para><i>extension (Optional)</i></para>
    /// <para>The file extension to give to the transformed files.  If unspecified the transformed files are automatically given an xml extension.  This is only used in conjunction with the Path and Output properties.</para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <Xml.XslTransform
    ///             XmlFile="C:\SourceFiles\file1.xml"
    ///             XslFile="C:\SourceFiles\Transform.xsl"
    ///             ResultFile="C:\TransformedFiles\Output.htm"
    ///         </Xml.XslTransform> 
    ///
    ///         <Xml.XslTransform
    ///             Path="C:\SourceFiles"
    ///             XslFile="C:\SourceFiles\Transform.xsl"
    ///             Output="C:\TransformedFiles"
    ///         </Xml.XslTransform> 
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class XslTransform : TaskBase
    {
        /// TODO: What this should do is allow Xml strings as input and xml strings as output
        /// but that would require more complexity as a "WriteToFile" task would be needed.
        /// It should also support parameters being passed into the XSL.

        private string xslFile = String.Empty;
        private string xmlFile = String.Empty;
        private string resultFile = String.Empty;
        private string path = String.Empty;
        private string output = String.Empty;
        private string extension = String.Empty;

        /// <summary>
        /// The full path and filename of the xsl file to be used in the transformation.
        /// </summary>
        /// <value>The full path and filename of the xsl file to be used in the transformation.</value>
        [Required]
        public string XslFile
        {
            get { return (xslFile == null ? String.Empty : this.xslFile); }
            set { this.xslFile = value; }
        }

        /// <summary>
        /// The full path and filename of the xml file to be transformed.
        /// </summary>
        /// <value>The full path and filename of the xml file to be transformed.</value>
        public string XmlFile
        {
            get { return (xmlFile == null ? String.Empty : this.xmlFile); }
            set { this.xmlFile = value; }
        }

        /// <summary>
        /// The full path and filename of the result of the transformation.
        /// </summary>
        /// <value>The full path and filename of the result of the transformation. This file will be created if it does not exist.</value>
        public string ResultFile
        {
            set { this.resultFile = value; }
            get { return (resultFile == null ? String.Empty : this.resultFile); }
        }

        /// <summary>
        /// The full path to a folder containing xml files requiring transformation.
        /// </summary>
        /// <value>The full path of the transformation source folder.</value>
        public string Path
        {
            set { this.path = value; }
            get { return (path == null ? String.Empty : this.path); }
        }

        /// <summary>
        /// The full path to a folder where transformed files will be placed.
        /// </summary>
        /// <value>The full path to the output folder.</value>
        public string Output
        {
            set { this.output = value; }
            get { return (output == null ? String.Empty : this.output); }
        }

        /// <summary>
        /// The file extension to give to transformed files.
        /// </summary>
        /// <value>The file extension given as 'htm'.</value>
        public string Extension
        {
            set { this.extension = value; }
            get { return (extension == null ? String.Empty : this.extension); }
        }

        /// <summary>
        /// Initializes a new instance of the Xsl class.
        /// </summary>
        public XslTransform()
        {
        }

        /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            #region Execute code

            if (XmlFile.Length > 0 && ResultFile.Length > 0)
            {
                XslCompiledTransform transform = new XslCompiledTransform();

                transform.Load(this.xslFile, XsltSettings.TrustedXslt, new XmlUrlResolver());
                transform.Transform(this.xmlFile, this.resultFile);
            }
            else if (Path.Length > 0 && Output.Length > 0)
            {
                XslCompiledTransform transform = new XslCompiledTransform();
                transform.Load(this.xslFile, XsltSettings.TrustedXslt, new XmlUrlResolver());
                
                if (System.IO.Directory.Exists(path))
                {
                    string[] files = System.IO.Directory.GetFiles(path, "*.xml");

                    string outputFile;

                    if (files.Length > 0)
                    {
                        if (!Directory.Exists(this.Output))
                        {
                            //create the output folder as it doesn't exist yet
                            Directory.CreateDirectory(this.Output);
                        }

                        foreach (string file in files)
                        {
                            Console.WriteLine(String.Format(CultureInfo.InvariantCulture, "Tranforming file {0}.", file));

                            if (Extension.Length == 0)
                            {
                                outputFile = System.IO.Path.Combine(this.Output, System.IO.Path.GetFileName(file));
                            }
                            else
                            {
                                outputFile = System.IO.Path.Combine(this.Output, System.IO.Path.GetFileNameWithoutExtension(file) + "." + this.Extension);
                            }
                            Log.LogMessage(MessageImportance.Low, "Output file is " + outputFile);
                            transform.Transform(file, outputFile);
                        }
                    }
                }
                else
                {
                    throw new TaskException("Xml.XslTransform.PathInvalid");
                }
            }
            else
            {
                throw new TaskException("Xml.XslTransform.InvalidArgs");
            }

            #endregion
        }
    }
}